<?php
/**
 * The PantsArticle class represents a single blog article.
 *
 * @author Ryan Grove <ryan@wonko.com>
 * @copyright Copyright (c) 2007 Ryan Grove. All rights reserved.
 * @license http://opensource.org/licenses/bsd-license.php New BSD License
 */
class PantsArticle extends PantsObject {
  public $id;
  public $title;
  public $content;
  public $posted;
  public $modified;
  
  public $comment_count;
  public $tags;
  
  private $comments;
  private $content_rendered;

  // -- Public Static Methods --------------------------------------------------
  
  /**
   * Creates a new PantsArticle object based on the form input in the $_POST
   * response.
   *
   * @return PantsArticle new article
   */
  public static function createFromResponse() {
    if ($id = Pants::getResponse('articleId')) {
      $article = PantsArticle::getById($id);
    }
    else {
      $article = new PantsArticle();
    }

    // Title.
    $article->title = trim(Pants::getResponse('articleTitle', $article->title));
    $article->title = str_replace(array('<', '>'), array('&lt;', '&gt;'),
        $article->title);

    // Content.
    $article->content = trim(Pants::getResponse('articleContent',
        $article->content));

    // Tags.
    if ($tags = Pants::getResponse('articleTags')) {
      $article->tags = explode(',', $tags, 64);

      foreach($article->tags as &$tagName) {
        $tagName = strtolower(trim($tagName));
      }

      sort($article->tags);
    }

    return $article;
  }

  /**
   * Gets the article with the specified id from the database.
   *
   * @param int $id article id
   * @return PantsArticle article with the specified id
   */
  public static function getById($id) {
    if (!$article = Pants::query('articles.getById', array('id' => $id))) {
      throw new PantsException('Invalid article id.');
    }

    return $article;
  } 

  /**
   * Gets an array of articles from the database that are tagged with the
   * specified tag id.
   *
   * @param int $tag_id tag id
   * @param int $limit maximum number of articles to return
   * @param int $offset offset at which to begin returning articles
   * @return array array of PantsArticle objects
   */
  public static function getByTagId($tag_id, $limit = 10, $offset = 0) {
    return Pants::query('articles.getByTagId', array(
      'tag_id' => $tag_id,
      'limit'  => $limit,
      'offset' => $offset
    ));
  }

  /**
   * Gets the total number of articles in the database.
   *
   * @return int total number of articles in the database
   */
  public static function getCount() {
    $result = Pants::query('articles.getCount');

    if ($result && $row = $result->fetch_array()) {
      return $row[0];
    }

    return 0;
  }

  /**
   * Gets an array of recently posted articles from the database.
   *
   * @param int $limit maximum number of articles to return
   * @param int $offset offset at which to begin returning articles
   * @return array array of PantsArticle objects
   */
  public static function getRecent($limit = 10, $offset = 0) {
    return Pants::query('articles.getRecent', array(
      'limit'  => $limit,
      'offset' => $offset
    ));
  }

  /**
   * Creates and returns a PantsArticle object built from the specified database
   * row.
   *
   * @param array $row database row
   * @return PantsArticle
   */
  public static function load($row) {
    return new PantsArticle($row['id'], $row['title'], $row['content'],
        $row['posted'], $row['modified'], $row['comment_count']);
  }

  /**
   * Performs a full text search and returns articles matching the specified
   * query.
   *
   * @param string $query search query
   * @return array array of PantsArticle objects
   */
  public static function search($query) {
    return Pants::query('articles.search', array('query' => $query));
  }

  // -- Public Instance Methods ------------------------------------------------
  
  /**
   * Initializes a new PantsArticle object.
   *
   * @param int $id article id
   * @param string $title article title
   * @param string $content article content
   * @param int $posted timestamp when article was first posted
   * @param int $modified timestamp when article was last modified
   * @param int $comment_count number of comments attached to the article
   * @param array $tags tags attached to the article
   */
  public function __construct($id = 0, $title = '', $content = '', $posted = 0,
      $modified = 0, $comment_count = 0, $tags = array()) {

    $this->id            = $id;
    $this->title         = $title;
    $this->content       = $content;
    $this->posted        = $posted == 0 ? time() : $posted;
    $this->modified      = $modified == 0 ? time() : $modified;
    $this->comment_count = $comment_count;
    $this->tags          = !count($tags) && $this->id != 0 ?
        PantsTag::getNamesByArticleId($this->id) : $tags;
  }

  /**
   * Gets an array of comments attached to this article.
   *
   * @return array array of PantsComment objects.
   */
  public function getComments() {
    if (!$this->comments) {
      $this->comments = PantsComment::getByArticleId($this->id);
    }
    
    return $this->comments;
  }

  /**
   * Gets the parsed and rendered content of this article.
   *
   * @return string parsed and rendered content of this article
   */
  public function getContent() {
    if (!$this->content_rendered) {
      $this->content_rendered = Pants::parseInfoboxes($this->content);
    }
    
    return $this->content_rendered;
  }
  
  /**
   * Persists this article to the database.
   *
   * @return mysqli_result database query result
   */
  public function save() {
    if ($this->id == 0) {
      $result = Pants::query('articles.create', array(
        'title'      => $this->title,
        'content'    => $this->content,
      ));

      if ($result) {
        $this->id = Pants::$db->getInsertId();
      }

      // Link tags.
      foreach($this->tags as $tagName) {
        PantsTag::createLink($this->id, $tagName);
      }
    }
    else {
      $result = Pants::query('articles.update', array(
        'id'         => $this->id,
        'title'      => $this->title,
        'content'    => $this->content,
      ));

      // Link tags.
      PantsTag::deleteLinks($this->id);

      foreach($this->tags as $tagName) {
        PantsTag::createLink($this->id, $tagName);
      }
    }

    return $result;
  }
}
?>